home *** CD-ROM | disk | FTP | other *** search
- Path: xanth!mcnc!rutgers!ukma!cwjcc!hal!ncoast!allbery
- From: jfh@rpp386.UUCP (The Beach Bum)
- Newsgroups: comp.sources.misc
- Subject: v05i061: "w" for Xenix/386
- Message-ID: <8807130000.AA13905@rpp386.UUCP>
- Date: 26 Nov 88 23:17:38 GMT
- Sender: allbery@ncoast.UUCP
- Reply-To: jfh@rpp386.UUCP (The Beach Bum)
- Lines: 529
- Approved: allbery@ncoast.UUCP
-
- Posting-number: Volume 5, Issue 61
- Submitted-by: "The Beach Bum" <jfh@rpp386.UUCP>
- Archive-name: xenix.w
-
- [This has been waiting for me to fold it into the main "w" code; I've finally
- admitted that it isn't going to happen anytime soon, so here it is. Sigh.
- ++bsa]
-
- i have hacked the hell out of your "w" command to produce one which
- works on sco xenix for a '386. i don't know what order you will
- receive the submissions in, but this is one of two. the other is
- a fuser command. oh yes, both of them need to be re-wrapped because
- my shar doesn't know about the perils of being mailed about.
-
- - john. (jfh@rpp386)
- --- beginning for w.shar ---
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # README
- # w.1l
- # w.c
- # This archive created: Fri Jul 8 09:15:25 1988
- # By: The Beach Bum (Big "D" Home for Wayward Hackers)
- export PATH; PATH=/bin:/usr/bin:$PATH
- if test -f 'README'
- then
- echo shar: "will not over-write existing file 'README'"
- else
- cat << \SHAR_EOF > 'README'
- [ This is the original README which was included with this package. Note
- that only "w" works. "avenrun" depends on system statistics which are
- not present in Xenix, and "csl" depends, in part, on "avenrun". -jfh ]
-
- The following are some programs which give you some familiar BSD utilities
- in a System V environment. The programs are:
-
- w - Yes, "w", as big as life! Requires...
- avenrun - A program to be invoked in /etc/rc which computes
- a "load average" from information in the "sysinfo"
- structure of the kernel. Based on a program by
- Phil Budne which forges "rwhod" packets for mixed
- networks; #define RWHOD for the original program.
- csl - I have no idea what the BSD "sysline" does, but this
- is my idea of a status line. The name stands for
- "cyclic status line"; it doesn't even attempt to
- fit everything into one line, instead it cycles
- through a set of "panels". See the man page.
- This also wants "avenrun" to be running.
-
- Note that "w" (and ONLY "w") can be compiled for System III or Xenix 3.0;
- this is in fact the default, use -DSYS5 to get the full version.
-
- No Makefile; the compile commands are trivial:
-
- cc -O -o w w.c -DSYS5 # omit the -DSYS5 for System III
- cc -O -o avenrun avenrun.c # add -DRWHOD for rwhod forgery
- cc -O -o csl csl.c
-
- "w" requires read permission on /dev/kmem, /dev/mem, and /dev/swap. "avenrun"
- requires read permission on /dev/kmem (to read the sysinfo structure). "csl"
- can run as a normal user program. On tdi2 we keep /dev/*mem and /dev/swap
- -r--r----- root/sys and have "avenrun" and "w" setgid sys.
-
- If someone wants to tell me what "sysline" under BSD does, I'd be interested
- in writing a real one. But "csl" is everything in one small package, so I
- will probably continue to use it.
-
- Enjoy!
-
- ++Brando
- SHAR_EOF
- fi
- if test -f 'w.1l'
- then
- echo shar: "will not over-write existing file 'w.1l'"
- else
- cat << \SHAR_EOF > 'w.1l'
- .TH W 1 local
- .SH NAME
- w \- display users and processes
- .SH SYNOPSIS
- .B w
- .SH DESCRIPTION
- .B W
- is a program which displays an "intelligent" listing of the current users,
- what they're doing, and how active they are. There are two basic kinds
- of information displayed: system information and per-user information.
- An example is shown below.
- .nf
-
- 10:55pm up 2 wks 2 days, 4 users
- User tty login@ idle JCPU PCPU what
- rhg tty6 10:36pm 12:20 12:20 csh
- robertd tty7 10:21pm 9:21 9:21 csh
- bobw tty13 10:26pm 160:35 149:43 rn
- allbery tty15 9:47pm 50:22 0:18 sh
-
- .fi
- The first line displays the current time, how long the system has been up,
- and the number of users.
- The other lines display for each user, the user's login name, the
- terminal the user is on, the time the user logged in, how long the user has
- been idle, the CPU time used by the current program and total CPU for the
- login session, and the current program.
- .SH FILES
- .ta \w'/dev/kmem 'u
- /dev/kmem System memory (the process table)
- .br
- /dev/mem In-core program images
- .br
- /dev/swap Swapped program images
- .br
- /dev Searches for terminals
- .br
- /etc/utmp Current system users and boot time
- .br
- /xenix System namelist
- .DT
- .SH NOTES
- .B W
- displays the process name as shown by
- .B ps(1)
- without the -f argument.
- .SH SEE ALSO
- ps(1), who(1).
- .SH BUGS
- JCPU and current process are both kludges. The former is really only the
- CPU of running programs in the terminal session, as Xenix does not retain
- user and system times for all programs in a session; the latter attempts to
- disregard background processes, but it is nearly impossible to successfully
- determine if a program is in the background or not. This is exacerbated by
- the fact that VAR csh(1)'s, when available, look suspiciously like
- background processes because they close their standard input.
- .PP
- If the user block is demand paged,
- .B w
- won't find it; I don't have access to a demand-paged system.
- .PP
- .B who -u
- and
- .B w
- have different ideas on what constitutes idle time; one uses time of last
- input, the other the time of last output.
- .PP
- It is possible that reading the summarized child's system and user times
- would produce a better approximation of JCPU. This is only likely, however,
- if the times are updated recursively.
- .PP
- Things can change while
- .B w
- is running; this occasionally causes the current program to be printed as
- "[can't stat]" or as "[interstice]".
- .PP
- If you want "w" to work correctly, get 4.2BSD.
- .PP
- It should really take options for the system namelist, memory, and
- swap files.
- .PP
- Because Xenix lacks the appropriate kernel variables, load averages are
- not available.
- .SH CREDIT
- Based on a utility written at the University of California at Berkeley.
- Original written by Brandon S. Allbery.
- Modified for SCO Xenix 386 by John F. Haugh II (jfh@rpp386).
- SHAR_EOF
- fi
- if test -f 'w.c'
- then
- echo shar: "will not over-write existing file 'w.c'"
- else
- cat << \SHAR_EOF > 'w.c'
- /*
- * %W% %E% %U% ncoast!bsa %Z%
- * %Z% Copyright (C) 1985 by Brandon S. Allbery, All Rights Reserved %Z%
- *
- * 8-Jul-88 John F. Haugh II (jfh@rpp386)
- * Major hacks to force to work on SCO Xenix 386
- */
-
- #ifndef lint
- static char _SccsId[] = "%W% %E% %U% ncoast!bsa %Z%";
- static char _CopyRt[] = "%Z% Copyright (C) 1985 by Brandon S. Allbery %Z%";
- #endif lint
-
- #include <stdio.h>
- #include <time.h>
- #include <signal.h>
- #include <a.out.h>
- #include <sys/types.h>
- #include <sys/page.h>
- #include <sys/seg.h>
- #include <sys/param.h>
- #include <sys/var.h>
- #include <sys/proc.h>
- #include <sys/dir.h>
- #include <sys/user.h>
- #include <sys/stat.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <sys/sysmacros.h>
- #include <utmp.h>
-
- #define UTMP "/etc/utmp"
- #ifndef KERNEL
- #define KERNEL "/xenix"
- #endif
- #define KMEM "/dev/kmem"
- #define PMEM "/dev/mem"
- #define SMEM "/dev/swap"
-
- #define MIN (60)
- #define HOUR (MIN * 60)
- #define DAY (HOUR * 24)
- #define WEEK (DAY * 7)
- #define MONTH (DAY * 30)
-
- FILE *kfd;
- FILE *mfd;
- FILE *sfd;
- FILE *utmp;
- long nproc;
- char _SObuf[BUFSIZ];
- daddr_t swplo;
- short mypid;
-
- struct xlist kernel[] = {
- {0, 0, 0, "_v"},
- {0, 0, 0, "_proc"},
- {0, 0, 0, "_swplo"},
- {0, 0, 0, "_lbolt"},
- {0, 0, 0, (char *) 0},
- };
-
- char *months[] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
- };
-
- struct tm *localtime();
- char *vtime();
- char *uptime();
- char *itoa();
-
- main() {
- struct utmp user;
- short ucnt;
- long now;
- struct var vars;
-
- setbuf(stdout, _SObuf);
- mypid = getpid();
- time(&now);
- if (xlist(KERNEL, kernel) == -1) {
- perror(KERNEL);
- exit(2);
- }
- if ((utmp = fopen(UTMP, "r")) == NULL) {
- perror(UTMP);
- exit(1);
- }
- ucnt = 0;
- while (fread(&user, sizeof user, 1, utmp) > 0) {
- if (user.ut_type != USER_PROCESS)
- continue;
- ucnt++;
- }
- if (kfd == NULL) {
- if ((kfd = fopen(KMEM, "r")) == NULL) {
- perror(KMEM);
- exit(3);
- }
- }
- fseek(kfd, kernel[0].xl_value, 0);
- fread(&vars, sizeof vars, 1, kfd);
- nproc = vars.v_proc;
- fseek(kfd, kernel[2].xl_value, 0);
- fread(&swplo, sizeof swplo, 1, kfd);
- if (mfd == NULL) {
- if ((mfd = fopen(PMEM, "r")) == NULL) {
- perror(PMEM);
- exit(4);
- }
- }
- if (sfd == NULL) {
- if ((sfd = fopen(SMEM, "r")) == NULL) {
- perror(SMEM);
- exit(5);
- }
- }
- printf(" %s up%s, %d users\nUser tty login@ idle JCPU PCPU what\n", vtime(&now), uptime(), ucnt);
- rewind(utmp);
- while (fread(&user, sizeof user, 1, utmp) > 0) {
- if (user.ut_type != USER_PROCESS)
- continue;
- show(&user);
- }
- fclose(utmp);
- exit(0);
- }
-
- char *uptime() {
- static char timebuf[128];
- struct proc swapper;
- struct user bootproc;
- long oldpos, now;
- short cnt, ocnt;
- long boottime = 0L;
-
- oldpos = fseek(kfd, 0L, 1);
- fseek(kfd, kernel[3].xl_value, 0);
- fread(&boottime, sizeof boottime, 1, kfd);
- now = boottime / HZ;
-
- if (now < 0L)
- return " with strange clock time";
- timebuf[0] = '\0';
- ocnt = 0;
- cnt = 0;
- while (now >= MONTH) {
- cnt++;
- now -= MONTH;
- }
- if (cnt > 0) {
- strcat(timebuf, itoa(cnt));
- strcat(timebuf, " mon");
- if (cnt > 1)
- strcat(timebuf, "s");
- if (++ocnt == 2)
- return timebuf;
- }
- cnt = 0;
- while (now >= WEEK) {
- cnt++;
- now -= WEEK;
- }
- if (cnt > 0) {
- strcat(timebuf, itoa(cnt));
- strcat(timebuf, " wk");
- if (cnt > 1)
- strcat(timebuf, "s");
- if (++ocnt == 2)
- return timebuf;
- }
- cnt = 0;
- while (now >= DAY) {
- cnt++;
- now -= DAY;
- }
- if (cnt > 0) {
- strcat(timebuf, itoa(cnt));
- strcat(timebuf, " day");
- if (cnt > 1)
- strcat(timebuf, "s");
- if (++ocnt == 2)
- return timebuf;
- }
- cnt = 0;
- while (now >= HOUR) {
- cnt++;
- now -= HOUR;
- }
- if (cnt > 0) {
- strcat(timebuf, itoa(cnt));
- strcat(timebuf, " hr");
- if (cnt > 1)
- strcat(timebuf, "s");
- }
- return timebuf;
- }
-
- char *itoa(n)
- int n; {
- static char buf[20];
-
- sprintf(buf, " %d", n);
- return buf;
- }
-
- findu (proc, slot, user)
- struct proc *proc;
- int slot;
- struct user *user;
- {
- struct proc *procs = (struct proc *) kernel[1].xl_value;
- long swapaddr;
- int i;
-
- if ((proc->p_flag & (SSWAP|SSPART)) || ! (proc->p_flag & SLOAD)) {
- swapaddr = proc->p_addr[0].te_frameno * NBPC;
- if (fseek (sfd, swapaddr, 0) == -1L)
- fprintf (stderr, "error in lseek\n");
- fread (user, sizeof *user, 1, sfd);
- } else {
- if (fseek (mfd, proc->p_addr[0].te_frameno * NBPC, 0) == -1L)
- fprintf (stderr, "error in lseek\n");
- fread (user, sizeof *user, 1, mfd);
- }
- if (user->u_procp - procs == slot)
- return (1);
- else
- return (0);
- }
-
- show(uinfo)
- struct utmp *uinfo;
- {
- struct stat sbuf;
- struct proc proc;
- struct user prog;
- char ttydev[16];
- long now, cnt, offset, jcpu;
- short mpid, isswap;
- FILE *ufd;
-
- strcpy(ttydev, "/dev/");
- strncpy(&ttydev[5], uinfo->ut_line, 8);
- ttydev[13] = '\0';
- if (stat(ttydev, &sbuf) != 0) {
- perror(ttydev);
- return;
- }
- time(&now);
- now -= sbuf.st_atime;
- printf("%-8.8s %-8.8s %7s ", uinfo->ut_name, uinfo->ut_line, vtime(&uinfo->ut_time));
- if (now > DAY)
- printf("%4dd", now / DAY);
- else if (now > HOUR)
- printf("%2d:%02d", now / HOUR, (now % HOUR) / 60);
- else if (now > MIN)
- printf("%5d", now / MIN);
- else
- printf(" ");
- putchar(' ');
- mpid = -1;
- jcpu = 0;
- for (cnt = 0; cnt < nproc; cnt++) {
- fseek (kfd, kernel[1].xl_value + (cnt * sizeof proc), 0);
- fread(&proc, sizeof proc, 1, kfd);
- if (proc.p_stat == 0 || proc.p_stat == SZOMB || proc.p_stat == SWAIT)
- continue;
-
- if (findu (&proc, cnt, &prog) == 0)
- continue;
-
- if (prog.u_ttyp == NULL)
- continue;
- if (sbuf.st_rdev != prog.u_ttyd)
- continue;
- jcpu += prog.u_utime + prog.u_stime +
- prog.u_cutime + prog.u_cstime;
- if (proc.p_pid == mypid)
- continue;
- if (proc.p_pid > mpid)
- mpid = proc.p_pid;
- }
- if (mpid == -1)
- printf("[can't stat]");
- else {
- fseek(kfd, kernel[1].xl_value, 0);
- for (cnt = 0; cnt < nproc; cnt++) {
- fread(&proc, sizeof proc, 1, kfd);
- if (proc.p_pid == mpid)
- break;
- }
- if (proc.p_pid != mpid)
- printf("[interstice]");
- else {
- if (findu (&proc, cnt, &prog) == 0)
- fprintf (stderr, "can't find parent\n");
-
- printf("%3d:%02d %3d:%02d ",
- (jcpu / HZ) / MIN, (jcpu / HZ) % MIN,
- ((prog.u_utime + prog.u_stime) / HZ) / MIN,
- ((prog.u_utime + prog.u_stime) / HZ) % MIN);
- prog.u_procp = &proc;
- pcmd(&prog);
- }
- }
- putchar('\n');
- }
-
- char *vtime(when)
- long *when; {
- struct tm then, now;
- static char buf[20];
- short hour, min, ampm;
- long clock;
-
- time(&clock);
- now = *localtime(&clock);
- then = *localtime(when);
- if (then.tm_mon != now.tm_mon || then.tm_mday != now.tm_mday) {
- sprintf(buf, "%s %2d", months[then.tm_mon], then.tm_mday);
- return buf;
- }
- min = then.tm_min;
- if (then.tm_hour == 0) {
- ampm = 'a';
- hour = 12;
- }
- else if (then.tm_hour > 0 && then.tm_hour < 12) {
- ampm = 'a';
- hour = then.tm_hour;
- }
- else if (then.tm_hour == 12) {
- ampm = 'p';
- hour = 12;
- }
- else {
- ampm = 'p';
- hour = then.tm_hour - 12;
- }
- sprintf(buf, "%d:%02d%cm", hour, min, ampm);
- return buf;
- }
-
- pcmd(uinfo)
- struct user *uinfo;
- {
- /* someday look up the user's command line */
- printf("%-.14s", uinfo->u_comm);
- }
- SHAR_EOF
- fi
- exit 0
- # End of shell archive
-